import type { ComputedRef, Ref } from "vue";

export interface UsePageFetchParams {
	pageSize: number;
	currentPage: number;
}

export type UsePageFetchCallBack<T extends any[]> = (
	params: UsePageFetchParams,
) => Promise<{ records: T; total: number }> | { records: T; total: number };

export interface UsePageOptions<T extends any[]> {
	/**
	 * 请求构造函数
	 */
	fetch: UsePageFetchCallBack<T>;

	/**
	 * 每页数量 默认:10
	 */
	initPageSize?: number;

	/**
	 * 初始化当前页， 默认:1
	 */
	initCurrentPage?: number;

	/**
	 * records使用ref 还是 shallowRef  默认为true  即shallowRef
	 */
	shallow?: boolean;

	/**
	 * 初始化后是否立即请求 默认true
	 */
	immediate?: boolean;

	/**
	 * 执行前清空数组 默认false
	 */
	resetOnExecute?: boolean;
}

/**
 * 分页请求返回参数
 */
export interface UsePageReturn<T extends any[]> {
	/**
	 * 分页数据
	 */
	records: Ref<T>;

	/**
	 * 当前页
	 */
	currentPage: Ref<number>;

	/**
	 * 每页数量
	 */
	pageSize: Ref<number>;

	/**
	 * 接口返回的总数量
	 */
	total: Readonly<Ref<number>>;

	/**
	 * 总页数
	 */
	totalPage: Readonly<Ref<number>>;
	/**
	 * 当前是否正在加载中
	 */
	isLoading: Readonly<Ref<boolean>>;
	/**
	 * 执行请求，可传入分页参数强制执行当前页或每页数量的改变，不传则单纯执行刷新
	 */
	execute: (params?: Partial<UsePageFetchParams>) => Promise<void>;
	/**
	 * 当前页的数组第一项索引
	 */
	startNo: ComputedRef<number>;
}

/**
 * 分页请求
 * @param options
 * @returns
 */
export function usePage<T extends any[]>(
	options: UsePageOptions<T>,
): UsePageReturn<T> {
	const refFn = (options?.shallow ?? true) ? shallowRef : ref;

	const records = refFn([] as any) as Ref<T>;

	const currentPage = ref(options.initCurrentPage ?? 1);

	const pageSize = ref(options.initPageSize ?? 10);

	const total = ref(0);

	const isLoading = ref(false);

	const totalPage = computed(() => {
		return Math.ceil(total.value / pageSize.value);
	});

	const startNo = computed(() => (currentPage.value - 1) * pageSize.value + 1);

	const _fetch = async () => {
		isLoading.value = true;

		options?.resetOnExecute && (records.value.length = 0);

		try {
			const res = await options.fetch({
				currentPage: currentPage.value,
				pageSize: pageSize.value,
			});
			records.value = res.records;
			total.value = Number(res.total) || 0;
		} finally {
			isLoading.value = false;
		}
	};

	watch([currentPage, pageSize], _fetch);

	const execute = async (params?: Partial<UsePageFetchParams>) => {
		if (currentPage.value === 1) {
			await _fetch();
			return;
		}
		if (!!params?.pageSize || !!params?.currentPage) {
			if (
				pageSize.value !== params?.pageSize ||
				currentPage.value !== params?.currentPage
			) {
				pageSize.value = Number(params?.pageSize) || pageSize.value;
				currentPage.value = Number(params?.currentPage) || currentPage.value;
			} else {
				await _fetch();
			}
		} else {
			await _fetch();
		}
	};

	const immediate = options?.immediate ?? true;

	immediate && execute();

	return {
		records,
		currentPage,
		pageSize,
		total: shallowReadonly(total),
		isLoading: shallowReadonly(isLoading),
		execute,
		startNo,
		totalPage,
	};
}
